server sent event基本上是由伺服器端單向送出資料的溝通機制,類似server push。這是一個與http相容的方法,只需要伺服器端送出特定的header、content-type及固定格式的內容就可以做到。類似的技術可以參考:
http://en.wikipedia.org/wiki/Push_technology
在瀏覽器端使用server sent event的物件叫做EventSource:
[Constructor(in DOMString url)]
interface EventSource {
readonly attribute DOMString URL;
// ready state
const unsigned short CONNECTING = 0;
const unsigned short OPEN = 1;
const unsigned short CLOSED = 2;
readonly attribute unsigned short readyState;
// networking
attribute Function onopen;
attribute Function onmessage;
attribute Function onerror;
void close();
};
EventSource implements EventTarget;
使用方式很簡單,當然伺服器要準備好一個送出event stream的URL,然後使用new EventSource(URL)來產生一個物件,利用他的onmessage來監聽事件:
<html lang="zh-TW">
<meta http-equiv="Content-Type" content="text/html; charset=utf8">
<style>
div {
border: solid 2px #336699;
margin: 10px;
padding: 5px;
border-radius: 5px;
vertical-align: top;
text-align: center;
display: inline-block;
}
.container {
background: #88BBFF;
width: 520px;
}
.msg {
background: #99CCFF;
border: dotted 1px #4477AA;
width: 480px;
margin: 0px;
text-align: left;
font-size: 12px;
}
</style>
<script>
function init() {
var es = new EventSource('test634.php');
es.addEventListener('message', function(e) {
var str = '';
str += '<li>[' + new Date() + ']: ';
str += e.data + '</li>\n';
document.getElementById('msg1').innerHTML += str;
}, false);
}
</script>
<div>
<div class="container">
Returned Messages.
<div id="msg1" class="msg"></div>
</div>
</div>
<script>
init();
</script>
伺服器端的php很簡單,只是每兩秒送出一個event...
<?php
header("Content-Type: text/event-stream");
flush();
$count = 0;
while(true) {
echo "data: " . "Server Sent Event round: " . $count . "\n\n";
$count++;
flush();
sleep(2);
}
每當伺服器連續兩個換行,EventSource就會把之前送出的資料當成一個事件,觸發onmessage。
我的伺服器有設定php最長執行時間,所以大約跑14~15次就會timeout,重新啟動程式,不過不會影響瀏覽器端的執行(這其實不一定,要看程式的結構及邏輯是否會影響每次重頭執行時的邏輯正確性)
熟悉server push跟long poll的人,應該很熟悉這樣的scenario,我想這也是Server Sent Event的目的,不過使用它可以讓這個流程變得很簡單。
不過目前EventSource似乎只有在Chrome7及Safari上才能執行,抓兩個執行畫面:
在寫PHP時需要注意,沒有使用flush()的話,內容會到程式結束才一次送出,所以上面的PHP程式中,我在header送出後及echo之後分別呼叫了一次flush(),讓伺服器分批送出內容。另外,由於Server Sent Event只支援UTF8編碼的資訊,所以伺服器端的程式送出的內容必須是UTF8編碼的。